﻿/*========================== 
 * @author 郑金泉
 * @desc 数据缓存类
 * ========================= */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using Obsidian.Edm;

namespace Obsidian.Data
{
    public class StaticCache : ICache
    {

        private static Hashtable htCahce = Hashtable.Synchronized(new Hashtable());


        public void Set<T>(string key, T value) where T : IModel, new()
        {
            Set<T>(key, value, -1, -1);
        }


        public void Set<T>(string key, T value, int validTime) where T : IModel, new()
        {
            Set<T>(key, value, validTime, -1);
        }


        public void Set<T>(string key, T value, int validTime, int holdTime) where T : IModel, new()
        {
            lock (htCahce)
            {
                string k = typeof(T).Name;
                Dictionary<object, Value<T>> dict;
                if (htCahce.ContainsKey(k))
                {
                    dict = (Dictionary<object, Value<T>>)htCahce[k];
                }
                else
                {
                    dict = new Dictionary<object, Value<T>>();
                    htCahce.Add(k, dict);
                }
                Value<T> val = new Value<T>(value, validTime, holdTime);
                dict[key] = val;
            }
        }


        public void Set(string key, object value)
        {
            Set(key, value, -1, -1);
        }


        public void Set(string key, object value, int validTime)
        {
            Set(key, value, validTime, -1);
        }

        public void Set(string key, object value, int validTime, int holdTime)
        {
            lock (htCahce)
            {
                string k = "__values__";
                Dictionary<object, Value<object>> dict;
                if (htCahce.ContainsKey(k))
                {
                    dict = (Dictionary<object, Value<object>>)htCahce[k];
                }
                else
                {
                    dict = new Dictionary<object, Value<object>>();
                    htCahce.Add(k, dict);
                }
                Value<object> val = new Value<object>(value, validTime, holdTime);
                dict[key] = val;
            }
        }

        public void Delete<T>(string key) where T : IModel, new()
        {
            lock (htCahce)
            {
                string k = typeof(T).Name;
                Dictionary<object, Value<T>> dict;
                if (htCahce.ContainsKey(k))
                {
                    dict = (Dictionary<object, Value<T>>)htCahce[k];
                    dict.Remove(key);
                }
            }
        }


        /// <summary>
        /// 判断缓存是否存在
        /// </summary>
        /// <returns></returns>
        public bool Exists<T>(string key) where T : IModel, new()
        {
            return Get<T>(key) != null;
        }


        public T Get<T>(string key) where T : IModel, new()
        {
            string k = typeof(T).Name;
            if (!htCahce.ContainsKey(k))
                return default(T);
            Dictionary<object, Value<T>> dict = (Dictionary<object, Value<T>>)htCahce[k];
            Value<T> val;
            if (!dict.TryGetValue(key, out val))
                return default(T);
            if (val.IsValid)
            {
                dict.Remove(key);
                return default(T);
            }
            return val.Data;
        }


        public object Get(string key)
        {
            string k = "__values__";
            if (!htCahce.ContainsKey(k))
                return null;
            Dictionary<object, Value<object>> dict = (Dictionary<object, Value<object>>)htCahce[k];
            Value<object> val;
            if (!dict.TryGetValue(key, out val))
                return null;
            if (val.IsValid)
            {
                dict.Remove(key);
                return null;
            }
            return val.Data;
        }


        private class Value<T>
        {

            private T data;
            private DateTime created = DateTime.Now;
            private DateTime accessTime = DateTime.Now;
            private int validTime;
            private int holdTime;

            public Value(T data, int validTime, int holdTime)
            {
                this.data = data;
                this.validTime = validTime;
                this.holdTime = holdTime;
            }

            public bool IsValid
            {
                get
                {
                    if (this.validTime > 0 && this.created.AddSeconds(this.validTime).CompareTo(DateTime.Now) > 0)
                        return false;
                    if (this.holdTime > 0 && this.accessTime.AddSeconds(this.holdTime).CompareTo(DateTime.Now) > 0)
                        return false;
                    return true;
                }
            }

            public T Data
            {
                get
                {
                    this.accessTime = DateTime.Now;
                    return data;
                }
            }

        }

    }
}
